/*
eventbus 包实现了一个轻量级事件总线系统，支持事件的发布与订阅机制。
该系统用于组件间的异步通信，通过解耦事件发送者与接收者，降低系统模块间的直接依赖，提高代码灵活性和可维护性。

实现全局事件总线

包含常用事件定义
*/
package eventbus

import (
	"errors" // 用于定义包内自定义错误类型
	"sync"   // 提供同步原语，确保事件总线在并发环境下的安全操作
	"time"
)

/* //* 事件总线核心实现，定义EventBus接口和内存实现，提供事件发布订阅机制，支持组件间异步通信和松耦合设计 */

// 事件总线配置
type Config struct {
	Type       string `json:"type"`        // 事件总线类型：memory, redis, kafka, etc.
	BufferSize int    `json:"buffer_size"` // 缓冲区大小
}

// 创建事件总线配置
func NewConfig() *Config {
	return &Config{
		Type:       "memory",
		BufferSize: 1000,
	}
}

// 根据配置创建事件总线
func CreateEventBus(config *Config) (EventBus, error) {
	switch config.Type {
	case "memory":
		return NewMemoryEventBus(), nil
		// 可以添加其他类型事件总线实现
		// case "redis":
		//     return NewRedisEventBus(config)
		// case "kafka":
		//     return NewKafkaEventBus(config)

	default:
		return NewMemoryEventBus(), nil
	}
}

// Event 事件接口，定义了所有事件必须实现的核心方法，规范事件的基本行为。
// 任何自定义事件都需实现此接口以被事件总线处理。
type Event interface {
	// Name 返回事件的唯一标识名称，用于事件总线匹配订阅者。
	// 返回值：事件名称字符串
	Name() string

	// Data 返回事件携带的具体数据，供订阅者处理事件时使用。
	// 返回值：事件数据（任意类型）
	Data() interface{}

	Timestamp() time.Time
}

// BaseEvent 是Event接口的基础实现，可直接使用或作为其他事件的嵌入结构体，
// 避免重复实现Name()和Data()方法。
type BaseEvent struct {
	name      string      // 事件的唯一标识名称，用于在事件总线中匹配对应的订阅者
	data      interface{} // 事件携带的业务数据，订阅者通过Data()方法获取
	timestamp time.Time
}

// NewBaseEvent 创建一个BaseEvent实例，用于快速生成基础事件。
// 参数：
//
//	name: 事件的唯一标识名称（例如："user.login"、"order.paid"）
//	data: 事件携带的业务数据（可为任意类型，如结构体、基本类型等）
//
// 返回值：
//
//	*BaseEvent: 初始化后的BaseEvent实例
func NewBaseEvent(name string, data interface{}) *BaseEvent {
	return &BaseEvent{
		name:      name, // 赋值事件名称
		data:      data, // 赋值事件数据
		timestamp: time.Now(),
	}
}

// Timestamp 返回时间戳
func (e *BaseEvent) Timestamp() time.Time {
	return e.timestamp
}

// Name 实现Event接口的Name方法，返回事件的标识名称。
// 返回值：
//
//	string: 事件名称
func (e *BaseEvent) Name() string {
	return e.name
}

// Data 实现Event接口的Data方法，返回事件携带的业务数据。
// 返回值：
//
//	interface{}: 事件数据（需由调用方断言为具体类型）
func (e *BaseEvent) Data() interface{} {
	return e.data
}

// Handler 定义事件处理器的函数类型，用于处理订阅到的事件。
// 当事件被发布时，事件总线会调用所有订阅该事件的Handler。
// 参数：
//
//	event: 被触发的事件实例（实现了Event接口），包含事件名称和数据
type Handler func(event Event)

// EventBus 事件总线接口，定义了事件总线的核心功能契约，
// 任何事件总线实现（如内存型、分布式型）都需遵循此接口。
type EventBus interface {
	// Subscribe 订阅指定名称的事件，当该事件被发布时，会触发传入的处理器。
	// 参数：
	//   eventName: 要订阅的事件名称（需与发布时的事件名称一致）
	//   handler: 事件触发时的处理函数（类型为Handler）
	// 返回值：
	//   error: 操作失败时返回错误（如事件总线已关闭），成功时返回nil
	Subscribe(eventName string, handler Handler) error

	// Unsubscribe 取消订阅指定名称的事件，移除对应的处理器。
	// 参数：
	//   eventName: 要取消订阅的事件名称
	//   handler: 要移除的事件处理器（需与订阅时传入的处理器一致）
	// 返回值：
	//   error: 操作失败时返回错误（如事件总线已关闭），成功时返回nil
	Unsubscribe(eventName string, handler Handler) error

	// Publish 发布一个事件，通知所有订阅该事件的处理器（异步执行）。
	// 参数：
	//   event: 要发布的事件实例（实现了Event接口）
	// 返回值：
	//   error: 操作失败时返回错误（如事件总线已关闭），成功时返回nil
	Publish(event Event) error

	// Close 关闭事件总线，释放内部资源，关闭后无法再进行订阅、发布等操作。
	// 返回值：
	//   error: 操作失败时返回错误，成功时返回nil
	Close() error

	// Type 返回事件总线类型
	Type() string
	// BufferSize 返回缓冲区大小
	BufferSize() int
}

// MemoryEventBus 基于内存的事件总线实现，适用于单进程内的组件通信。
// 所有订阅关系和事件处理均在内存中完成，无需外部存储依赖。
type MemoryEventBus struct {
	subscribers map[string][]Handler // 存储事件订阅关系：key为事件名称，value为该事件的所有处理器列表
	mu          sync.RWMutex         // 读写锁，保证并发安全：读操作（如Publish）用RLock，写操作（如Subscribe/Unsubscribe）用Lock
	closed      bool                 // 标记事件总线是否已关闭：true表示已关闭，所有操作将返回错误
	config      *Config
}

// NewMemoryEventBus 创建一个MemoryEventBus实例，初始化内部订阅关系映射。
// 返回值：
//
//	*MemoryEventBus: 初始化后的内存事件总线实例
func NewMemoryEventBus() *MemoryEventBus {
	return &MemoryEventBus{
		subscribers: make(map[string][]Handler), // 初始化订阅关系为空map
		config:      NewConfig(),
	}
}

// NewMemoryEventBusWithConfig 使用配置创建内存事件总线
func NewMemoryEventBusWithConfig(config *Config) *MemoryEventBus {
	return &MemoryEventBus{
		subscribers: make(map[string][]Handler),
		config:      config,
	}
}

// Type 返回事件总线类型
func (bus *MemoryEventBus) Type() string {
	return "memory"
}

// BufferSize 返回缓冲区大小
func (bus *MemoryEventBus) BufferSize() int {
	return bus.config.BufferSize
}

// Subscribe 实现EventBus接口的Subscribe方法，为指定事件添加处理器。
func (bus *MemoryEventBus) Subscribe(eventName string, handler Handler) error {
	bus.mu.Lock()         // 加写锁：防止并发订阅导致的map竞争问题
	defer bus.mu.Unlock() // 函数退出时自动释放锁

	if bus.closed { // 检查总线是否已关闭
		return ErrEventBusClosed // 已关闭则返回关闭错误
	}

	// 将处理器添加到对应事件的列表中：若事件名不存在，map会自动创建键值对
	bus.subscribers[eventName] = append(bus.subscribers[eventName], handler)
	return nil // 订阅成功，返回nil
}

// Unsubscribe 实现EventBus接口的Unsubscribe方法，从指定事件中移除处理器。
func (bus *MemoryEventBus) Unsubscribe(eventName string, handler Handler) error {
	bus.mu.Lock()         // 加写锁：防止并发取消订阅导致的map竞争问题
	defer bus.mu.Unlock() // 函数退出时自动释放锁

	if bus.closed { // 检查总线是否已关闭
		return ErrEventBusClosed // 已关闭则返回关闭错误
	}

	// 尝试获取该事件的处理器列表
	if handlers, exists := bus.subscribers[eventName]; exists {
		// 遍历处理器列表，查找目标处理器
		for i, h := range handlers {
			// 注意：此处通过函数指针地址比较，若处理器为匿名函数可能无法正确匹配（需业务层保证处理器唯一性）
			if &h == &handler {
				// 移除找到的处理器：拼接当前索引前后的切片，覆盖原列表
				bus.subscribers[eventName] = append(handlers[:i], handlers[i+1:]...)
				break // 找到后退出循环，避免重复移除
			}
		}
	}

	return nil // 无论是否找到处理器，均返回nil（设计上不区分"未找到"与"成功移除"）
}

// Publish 实现EventBus接口的Publish方法，发布事件并异步通知所有订阅者。
func (bus *MemoryEventBus) Publish(event Event) error {
	bus.mu.RLock()         // 加读锁：允许并发读取订阅列表，不阻塞其他读操作
	defer bus.mu.RUnlock() // 函数退出时自动释放锁

	if bus.closed { // 检查总线是否已关闭
		return ErrEventBusClosed // 已关闭则返回关闭错误
	}

	// 根据事件名称获取所有订阅的处理器
	if handlers, exists := bus.subscribers[event.Name()]; exists {
		// 遍历处理器列表，异步执行每个处理器（避免阻塞发布操作）
		for _, h := range handlers {
			go h(event) // 启动goroutine执行处理器，实现异步通知
		}
	}

	return nil // 发布成功（即使无订阅者也视为成功）
}

// Close 实现EventBus接口的Close方法，关闭事件总线并清理资源。
func (bus *MemoryEventBus) Close() error {
	bus.mu.Lock()         // 加写锁：确保关闭操作的原子性
	defer bus.mu.Unlock() // 函数退出时自动释放锁

	bus.closed = true                            // 标记总线为关闭状态
	bus.subscribers = make(map[string][]Handler) // 清空订阅关系，释放内存
	return nil                                   // 关闭成功
}

// 包内错误变量定义

// ErrEventBusClosed 表示事件总线已关闭时的错误（所有操作在总线关闭后调用均返回此错误）
var (
	ErrEventBusClosed = errors.New("event bus closed")
)
